/**
 @file ctc_at_l3if.c

 @date 2009-12-10

 @version v2.0

This file contains all L3 interface related Duet2 APIs implemention.

*/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_const.h"
#include "ctc_at_l3if.h"
#include "sys_usw_common.h"
#include "sys_usw_wb_common.h"
#include "sys_usw_l3if.h"

/****************************************************************
*
* Defines and Macros
*
****************************************************************/

/***************************************************************
 *
 * Structure
 *
 ***************************************************************/

/***************************************************************
 *
 * Functions
 *
 ***************************************************************/

/**********************************************************************************
                      Define API function interfaces
***********************************************************************************/

int32
ctc_at_l3if_init(uint8 lchip, void* l3if_global_cfg)
{
    uint8 lchip_start = 0;
    uint8 lchip_end = 0;
    ctc_l3if_global_cfg_t global_cfg;

    LCHIP_CHECK(lchip);
    if (NULL == l3if_global_cfg)
    {
        sal_memset(&global_cfg, 0, sizeof(ctc_l3if_global_cfg_t));
        global_cfg.max_vrfid_num = 256;
        global_cfg.ipv4_vrf_en = TRUE;
        global_cfg.ipv6_vrf_en = TRUE;
        global_cfg.rtmac_mode = 0;
    }
    else
    {
        sal_memcpy(&global_cfg, l3if_global_cfg, sizeof(ctc_l3if_global_cfg_t));
    }

    CTC_AT_FOREACH_LCHIP(lchip_start, lchip_end, 1)
    {
        CTC_ERROR_RETURN(sys_usw_l3if_init(lchip, &global_cfg));
    }

    return CTC_E_NONE;
}

int32
ctc_at_l3if_deinit(uint8 lchip)
{
    uint8 lchip_start = 0;
    uint8 lchip_end   = 0;

    LCHIP_CHECK(lchip);
    CTC_AT_FOREACH_LCHIP(lchip_start, lchip_end, 1)
    {
        CTC_ERROR_RETURN(sys_usw_l3if_deinit(lchip));
    }
    
    return CTC_E_NONE;
}

int32
ctc_at_l3if_create(uint8 lchip, uint16 l3if_id, ctc_l3if_t* l3_if)
{
    int32 ret          = CTC_E_NONE;
    uint8 pp_base   = SYS_PP_BASE(lchip);
    uint8 lchip_start  = pp_base;
    uint8 lchip_end    = pp_base;

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);

    CTC_ERROR_RETURN(sys_usw_l3if_create(pp_base, l3if_id, l3_if));

    if (CTC_L3IF_TYPE_SUB_IF == l3_if->l3if_type)
    {
        if (CTC_IS_LINKAGG_PORT(l3_if->gport))
        {
            if (MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_SCL))
            {
                lchip_end = pp_base + SYS_PP_NUM(lchip);
            }
            else
            {
                lchip_end = pp_base + 1;
            }
        }
        else if (sys_usw_chip_is_local(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(l3_if->gport)))
        {
            if (MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_SCL))
            {
                SYS_MAP_GPORT_TO_LCHIP1(l3_if->gport, lchip);
            }
            else
            {
                SYS_MAP_GPORT_TO_LCHIP(l3_if->gport, lchip);
                lchip = SYS_PP_BASE(lchip);
            }
            lchip_start  = lchip;
            lchip_end    = lchip + 1;
        }
    }
    
    for (lchip = lchip_start; lchip < lchip_end; lchip++)
    {
        CTC_ERROR_GOTO(sys_usw_l3if_create_subif(lchip, l3if_id, l3_if), ret, error0);
    }

    return CTC_E_NONE;

error0:
    
    CTC_AT_FOREACH_ROLLBACK(lchip_start,lchip_end)
    {
        sys_usw_l3if_delete_subif(lchip,l3if_id,l3_if);
    }

    sys_usw_l3if_delete(pp_base, l3if_id, l3_if);

    return ret;
}

int32
ctc_at_l3if_destory(uint8 lchip, uint16 l3if_id, ctc_l3if_t* l3_if)
{
    uint8 i    = 0;
    uint8 pp_base       = SYS_PP_BASE(lchip);
    uint8 lchip_start  = pp_base;
    uint8 lchip_end    = pp_base;


    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);

    if (CTC_L3IF_TYPE_SUB_IF == l3_if->l3if_type)
    {
        if (CTC_IS_LINKAGG_PORT(l3_if->gport))
        {
            if (MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_SCL))
            {
                lchip_end = pp_base + SYS_PP_NUM(lchip);
            }
            else
            {
                lchip_end = pp_base + 1;
            }
        }
        else if (sys_usw_chip_is_local(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(l3_if->gport)))
        {
            if (MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_SCL))
            {
                SYS_MAP_GPORT_TO_LCHIP1(l3_if->gport, lchip);
            }
            else
            {
                SYS_MAP_GPORT_TO_LCHIP(l3_if->gport, lchip);
                lchip = SYS_PP_BASE(lchip);
            }
            lchip_start  = lchip;
            lchip_end    = lchip + 1;
        }
    }

    for (i = lchip_start; i < lchip_end; i++)
    {
        sys_usw_l3if_delete_subif(i, l3if_id, l3_if);
    }

    return sys_usw_l3if_delete(pp_base, l3if_id, l3_if);

}

int32
ctc_at_l3if_get_l3if_id(uint8 lchip, ctc_l3if_t* p_l3_if, uint16* l3if_id)
{

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_id(lchip, p_l3_if, l3if_id));

    return CTC_E_NONE;
}

int32
ctc_at_l3if_set_property(uint8 lchip, uint16 l3if_id, ctc_l3if_property_t l3if_prop, uint32 value)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_set_property(SYS_PP_BASE(lchip), l3if_id, l3if_prop, value));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_set_property_array(uint8 lchip, uint16 l3if_id, ctc_property_array_t* l3if_prop, uint16* array_num)
{
    uint16 loop        = 0;
    int32 ret          = CTC_E_NONE;

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_PTR_VALID_CHECK(l3if_prop);
    CTC_PTR_VALID_CHECK(array_num);
    for(loop = 0; loop < *array_num; loop++)
    {
        ret = sys_usw_l3if_set_property(lchip, l3if_id, l3if_prop[loop].property, l3if_prop[loop].data);
        if(ret && ret != CTC_E_NOT_SUPPORT)
        {
            *array_num = loop;
            return ret;
        }
    }

    /*if sucess keep array num as itself*/
    return CTC_E_NONE;
}

int32
ctc_at_l3if_get_property(uint8 lchip, uint16 l3if_id, ctc_l3if_property_t l3if_prop, uint32* value)
{

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_get_property(lchip, l3if_id, l3if_prop, value));

    return CTC_E_NONE;
}

int32
ctc_at_l3if_set_acl_property(uint8 lchip, uint16 l3if_id, ctc_acl_property_t* acl_prop)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_set_acl_property(SYS_PP_BASE(lchip), l3if_id, acl_prop));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_get_acl_property(uint8 lchip, uint16 l3if_id, ctc_acl_property_t* acl_prop)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_get_acl_property(lchip, l3if_id, acl_prop));

    return CTC_E_NONE;
}

int32
ctc_at_l3if_set_router_mac(uint8 lchip, mac_addr_t mac_addr)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_set_router_mac(lchip, mac_addr));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_get_router_mac(uint8 lchip, mac_addr_t mac_addr)
{

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_get_router_mac(lchip, mac_addr));

    return CTC_E_NONE;
}

int32
ctc_at_l3if_set_interface_router_mac(uint8 lchip, uint16 l3if_id, ctc_l3if_router_mac_t router_mac)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);

    CTC_ERROR_RETURN(sys_usw_l3if_set_interface_router_mac(SYS_PP_BASE(lchip), l3if_id, router_mac));

    return CTC_E_NONE;
}

int32
ctc_at_l3if_get_interface_router_mac(uint8 lchip, uint16 l3if_id, ctc_l3if_router_mac_t* router_mac)
{

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_get_interface_router_mac(SYS_PP_BASE(lchip), l3if_id, router_mac));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_create_ecmp_if(uint8 lchip, ctc_l3if_ecmp_if_t* p_ecmp_if)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_ecmp_if);
    CTC_ERROR_RETURN(sys_usw_l3if_create_ecmp_if(SYS_PP_BASE(lchip), p_ecmp_if));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_destory_ecmp_if(uint8 lchip, uint16 ecmp_if_id)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_destory_ecmp_if(SYS_PP_BASE(lchip), ecmp_if_id));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_add_ecmp_if_member(uint8 lchip, uint16 ecmp_if_id, uint16 l3if_id)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_add_ecmp_if_member(SYS_PP_BASE(lchip), ecmp_if_id, l3if_id));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_remove_ecmp_if_member(uint8 lchip, uint16 ecmp_if_id, uint16 l3if_id)
{
    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    CTC_ERROR_RETURN(sys_usw_l3if_remove_ecmp_if_member(SYS_PP_BASE(lchip), ecmp_if_id, l3if_id));
    return CTC_E_NONE;
}

int32
ctc_at_l3if_add_router_mac_entry(uint8 lchip, uint32 entry_id, ctc_l3if_rmac_entry_t* rmac_entry)
{
    uint8 lchip_start  = 0;
    uint8 lchip_end    = 0;
    uint16 pp_bmp_tmp       = 0;
    uint16 pp_bmp       = 0;
    uint8 is_update    = 0;
    int32 ret          = CTC_E_NONE;

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);

    if(!MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF))
    {
        lchip = SYS_PP_BASE(lchip);
        return sys_usw_l3if_add_router_mac_entry(lchip, entry_id, rmac_entry);
    }

    pp_bmp_tmp = SYS_PP_BMP_MAPPING(rmac_entry->pp_bmp);
    ret = sys_usw_l3if_lookup_entry_hash(lchip, entry_id, &pp_bmp);
    if((!ret) && pp_bmp_tmp != pp_bmp)
    {
        return CTC_E_INVALID_PARAM;
    }
    else if(!ret)
    {
        is_update = 1;
    }
    ret = CTC_E_NONE;
    
    CTC_AT_FOREACH_LCHIP(lchip_start, lchip_end, 1)
    {
        if (!CTC_IS_BIT_SET(pp_bmp_tmp, lchip - lchip_start))
        {
            continue;
        }
        CTC_AT_FOREACH_ERROR_RETURN(ret, sys_usw_l3if_add_router_mac_entry(lchip, entry_id, rmac_entry));
        CTC_BIT_SET(pp_bmp, (lchip-lchip_start));
    }

    if (pp_bmp && !is_update)
    {
        sys_usw_l3if_add_entry_hash(lchip_start, entry_id, pp_bmp);
    }

    return ret;
}

int32
ctc_at_l3if_remove_router_mac_entry(uint8 lchip, uint32 entry_id)
{
    uint8 lchip_start  = 0;
    uint8 lchip_end    = 0;
    uint16 pp_bmp       = 0;
    int32 ret          = CTC_E_NONE;

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);
    if(!MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF))
    {
        lchip = SYS_PP_BASE(lchip);
        return sys_usw_l3if_remove_router_mac_entry(lchip, entry_id);
    }

    ret = sys_usw_l3if_lookup_entry_hash(lchip, entry_id, &pp_bmp);
    if(ret)
    {
        return CTC_E_NOT_EXIST;
    }

    CTC_AT_FOREACH_LCHIP(lchip_start, lchip_end, 1)
    {
        if (!CTC_IS_BIT_SET(pp_bmp, lchip - lchip_start))
        {
            continue;
        }

        CTC_AT_FOREACH_ERROR_RETURN2(ret, sys_usw_l3if_remove_router_mac_entry(lchip, entry_id));
    }
    sys_usw_l3if_remove_entry_hash(lchip_start, entry_id);

    return ret;
}

int32
ctc_at_l3if_get_router_mac_entry(uint8 lchip, uint32 entry_id, ctc_l3if_rmac_entry_t* rmac_entry)
{
    uint8 pp_id        = 0;
    int32 ret          = CTC_E_NONE;
    uint16 pp_bmp      = 0;

    FEATURE_SUPPORT_CHECK(CTC_FEATURE_L3IF);
    LCHIP_CHECK(lchip);

    if(!MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF))
    {
        return sys_usw_l3if_get_router_mac_entry(lchip, entry_id, rmac_entry);
    }

    if(MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF) && rmac_entry->pp_bmp)
    {
        CTC_BMP_FIRST_VALID(&rmac_entry->pp_bmp, SYS_PP_NUM(lchip), pp_id);
        lchip = SYS_PP_BASE(lchip) + pp_id;
    }
    else
    {
        ret = sys_usw_l3if_lookup_entry_hash(lchip, entry_id, &pp_bmp);
        if(ret)
        {
            return CTC_E_NOT_EXIST;
        }
        CTC_BMP_FIRST_VALID(&pp_bmp, SYS_PP_NUM(lchip), pp_id);
        lchip = SYS_PP_BASE(lchip) + pp_id;
        rmac_entry->pp_bmp = pp_bmp;
    }

    CTC_ERROR_RETURN(sys_usw_l3if_get_router_mac_entry(lchip, entry_id, rmac_entry));

    return ret;
}

